/*******************************************************************************
 * Package: com.song.flowable.service.impl
 * Type:    ProcessInstanceServiceImpl
 * Date:    2023-11-28 22:24
 *
 * Copyright (c) 2023 LTD All Rights Reserved.
 *
 * You may not use this file except in compliance with the License.
 *******************************************************************************/
package com.song.flowable.service.impl;

import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.song.common.util.CommUtil;
import com.song.common.constants.CommonConstant;
import com.song.flowable.convert.ProcessInstancesConvert;
import com.song.flowable.dto.BatchDeleteProcessInstanceDTO;
import com.song.flowable.dto.DoneDTO;
import com.song.flowable.service.ProcessInstanceService;
import com.song.flowable.vo.ProcessInstancesVO;
import com.song.flowable.vo.QueryHistoryActivityVO;
import lombok.RequiredArgsConstructor;
import org.flowable.engine.HistoryService;
import org.flowable.engine.RuntimeService;
import org.flowable.engine.TaskService;
import org.flowable.engine.history.HistoricProcessInstance;
import org.flowable.engine.history.HistoricProcessInstanceQuery;
import org.flowable.engine.runtime.ProcessInstance;
import org.flowable.engine.task.Comment;
import org.flowable.task.api.history.HistoricTaskInstance;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;


/**
 * 功能描述： 流程实例
 *
 * @author Songxianyang
 * @date 2023-11-28 22:24
 */
@Service
@RequiredArgsConstructor
public class ProcessInstanceServiceImpl implements ProcessInstanceService {

    private final RuntimeService runtimeService;
    private final HistoryService historyService;
    private final TaskService taskService;

    /**
     * 获得指定流程实例
     *
     * @param processInstanceId
     * @return HistoricProcessInstance
     */
    @Override
    public HistoricProcessInstance getProcessInstance(String processInstanceId) {
        HistoricProcessInstance historicProcessInstance = historyService.createHistoricProcessInstanceQuery().processInstanceId(processInstanceId).singleResult();
        return historicProcessInstance;
    }

    /**
     * 终止流程(撤回)
     *
     * @param processInstanceId
     * @param reason
     * @return
     */
    @Override
    public Boolean deleteProcessInstanceById(String processInstanceId, String reason) {
        runtimeService.deleteProcessInstance(processInstanceId, reason);
        return Boolean.TRUE;
    }

    /**
     * 批量终止、撤回流程实例
     *
     * @param dto
     * @return
     */
    @Override
    public Boolean batchDeleteProcessInstanceById(BatchDeleteProcessInstanceDTO dto) {
        runtimeService.bulkDeleteProcessInstances(dto.getProcessInstanceIds(), dto.getReason());
        return Boolean.TRUE;
    }

    /**
     * 根据流程实例id查询当前历史流程记录
     *
     * @param processInstanceId
     * @return
     */
    @Override
    public List<QueryHistoryActivityVO> historicActivityInstances(String processInstanceId) {
        List<QueryHistoryActivityVO> vos = new ArrayList<>();
        // 获得任务列表
        List<HistoricTaskInstance> tasks = historyService.createHistoricTaskInstanceQuery()
                .processInstanceId(processInstanceId)
                .orderByHistoricTaskInstanceStartTime().asc() // 创建时间倒序
                .list();
        for (HistoricTaskInstance instance : tasks) {
            QueryHistoryActivityVO vo = new QueryHistoryActivityVO();
            vo.setHistoricActivityInstanceId(instance.getId());
            vo.setProcessDefinitionId(instance.getProcessDefinitionId());
            vo.setStartTime(instance.getStartTime());
            vo.setEndTime(instance.getEndTime());
            vo.setTaskNodeId(instance.getTaskDefinitionKey());
            vo.setTaskNodeName(instance.getName());
            vo.setAssignee(instance.getAssignee());
            // 赋值审批意见
            String taskId = instance.getId();
            List<Comment> taskComments = taskService.getTaskComments(taskId);
            for (Comment taskComment : taskComments) {
                String message = taskComment.getFullMessage();
                vo.setFullMessage(message);
                continue;
            }
            vos.add(vo);
        }
        return vos;
    }


    /**
     * 判断传入流程实例在运行中是否存在
     *
     * @param processInstanceId
     * @return
     */
    @Override
    public Boolean isExistProcIntRunning(String processInstanceId) {
        ProcessInstance processInstance = runtimeService.createProcessInstanceQuery().processInstanceId(processInstanceId).singleResult();
        if (processInstance == null) {
            return false;
        }
        return true;
    }

    /**
     * 我发起的流程实例列表
     *
     * @param
     * @return
     */
    @Override
    public Page<ProcessInstancesVO> listByUserId(DoneDTO dto) {
        Page<ProcessInstancesVO> page = new Page<>();

        HistoricProcessInstanceQuery query = historyService.createHistoricProcessInstanceQuery();
        // 已终止流程实例
        if (CommUtil.equals(dto.getIfEnd(), 1)) {
            query.deleted();
        } else {
            // 未终止流程实例
            query.notDeleted();
        }
        if (CommUtil.isNotEmpty(dto.getUserId())) {
            query.startedBy(dto.getUserId());
        }
        query.orderByProcessInstanceStartTime().desc();

        List<HistoricProcessInstance> historicProcessInstances = new ArrayList<>();
        if (CommUtil.isNotEmpty(dto.getPageSize()) && CommUtil.isNotEmpty(dto.getPage())) {
            historicProcessInstances = query.listPage(dto.getPageSize() * (dto.getPage() - 1), dto.getPageSize());
        } else {
            historicProcessInstances = query.list();
        }
        page.setTotal(query.count());
        if (CommUtil.isEmpty(historicProcessInstances)) {
            page.setRecords(Collections.EMPTY_LIST);
            return page;
        }
        List<ProcessInstancesVO> processInstancesVOS = ProcessInstancesConvert.INSTANCE.toVoList(historicProcessInstances);
        page.setRecords(processInstancesVOS);
        return page;
    }

    /**
     * 挂起流程实例(停止、暂停）或（唤醒、激活）被挂起的流程实例
     * @param processInstanceId
     * @param state   1:激活、2：挂起
     * @return
     */
    @Override
    public Boolean stopOrActivate(String processInstanceId,String state) {
        //
        if (CommUtil.equals( CommonConstant.one,state)) {
            runtimeService.activateProcessInstanceById(processInstanceId);
        }
        if (CommUtil.equals(CommonConstant.two, state)) {
            runtimeService.suspendProcessInstanceById(processInstanceId);
        }
        return Boolean.TRUE;
    }
}
